package indi.zhifa.learn.jenkins.helloworld2.web.service.algorithm;

import indi.zhifa.learn.jenkins.helloworld2.web.entity.enums.EValueType;
import indi.zhifa.learn.jenkins.helloworld2.web.entity.request.DocKeyPass;
import indi.zhifa.learn.jenkins.helloworld2.web.entity.request.DocKeyPassConfig;
import indi.zhifa.learn.jenkins.helloworld2.web.entity.request.DocKeySetItem;
import indi.zhifa.learn.jenkins.helloworld2.web.service.algorithm.datastructure.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;

import java.util.List;
import java.util.Map;

@Slf4j
public class PdfDocument {

    DocResultSet mDocResultSet;
    DocKeyPassConfig mKeyConfigs;
    PdfOutlineTreeRoot mPdfOutlineTreeRoot;

    public PdfDocument(DocKeyPassConfig pKeyConfigs){
        mDocResultSet = new DocResultSet();
        mKeyConfigs = pKeyConfigs;
    }

    public Map<String,Object> getKvs(){
        return mDocResultSet.getValues();
    }

    public DocResultSet getDocResultSet(){
        return mDocResultSet;
    }

    /**
     * 使用简单暴力的字符串匹配算法实现
     *
     * @param pDoc
     */
    public void handlePdfSimple(PDDocument pDoc) throws Exception {
        // 生成目录树
        mPdfOutlineTreeRoot = new PdfOutlineTreeRoot();
        mPdfOutlineTreeRoot.init(pDoc);

        List<DocKeyPass> passes = mKeyConfigs.getPasses();

        // 遍历所有pass
        for(DocKeyPass docKeyPass : passes){
            // 遍历pass中的所有key配置
            PassResultItem passResultItem = new PassResultItem(docKeyPass.getOutlines());
            mDocResultSet.getPassResults().add(passResultItem);
            DocKeySetItem[] pass = docKeyPass.getPass();
            String[] outlines = docKeyPass.getOutlines();
            PdfOutlineTreeNode pdfOutlineTreeNode = null;
            try{
                pdfOutlineTreeNode = mPdfOutlineTreeRoot.findNode(outlines);
                passResultItem.setSuccess(true);
                passResultItem.setPageBegin(pdfOutlineTreeNode.getBeginPage());
                passResultItem.setPageEnd(pdfOutlineTreeNode.getEndPage());
            }catch (Exception ex){
                passResultItem.setSuccess(false);
                passResultItem.setErrInfo(ex.toString());
                continue;
            }

            PDFTextStripper pdfStripper = new PDFTextStripper();
            pdfStripper.setStartBookmark(pdfOutlineTreeNode.getBeginBookMark());
            pdfStripper.setEndBookmark(pdfOutlineTreeNode.getEndBookMark());
            String parsedText = pdfStripper.getText(pDoc);
            // 去掉所有的换行
            StringBuilder parsedTextSb = new StringBuilder();
            for(int i=0;i<parsedText.length();i++){
                char c = parsedText.charAt(i);
                if(!(c == '\n' || c== '\r' )){
                    parsedTextSb.append(c);
                }
            }
            parsedText = parsedTextSb.toString();
            int loc = 0;

            for(DocKeySetItem docKeySetItem : pass){
                String prefix = docKeySetItem.getRegexPrefix();
                String suffix = docKeySetItem.getRegexSuffix();
                int times = docKeySetItem.getTimes();
                String[] result = new String[1];
                int newLoc = findKeyResult(parsedText,loc,prefix,suffix,times,result);
                DocValueResult docValueResult = new DocValueResult();
                docValueResult.setKey(docKeySetItem.getKey());
                passResultItem.getResults().add(docValueResult);
                if(newLoc == -1){
                    String desc = docKeySetItem.purposeDesc();
                    docValueResult.setSuccess(false);
                    docValueResult.setErrInfo(desc+" 无法找到");
                    continue;
                }else{
                    String rawResult = result[0];
                    Object retrieveResult = null;
                    try{
                        retrieveResult = retrieveValue(rawResult,docKeySetItem.getValueType());
                        docValueResult.setSuccess(true);
                        docValueResult.setValue(retrieveResult);
                    }catch (Exception ex){
                        docValueResult.setSuccess(false);
                        docValueResult.setErrInfo(rawResult+" 无法转化为 "+docKeySetItem.getValueType());
                    }
                }
            }
        }
    }

    private Object retrieveValue(String pRawValue, EValueType pValueType){
        pRawValue = pRawValue.trim();
        switch (pValueType) {
            case STRING:
                return pRawValue;
            case INTEGER:
                int iVal = Integer.parseInt(pRawValue);
                return iVal;
            case DOUBLE:
                double dVal = Double.parseDouble(pRawValue);
                return dVal;
        }
        return null;
    }


    private int findKeyResult(String pContext,int pLoc,String pPrefix, String pSuffix, int pTimes, String[] pResult){
        int loc = pLoc;
        while (pTimes-- > 0 && loc < pContext.length()){
            loc = pContext.indexOf(pPrefix,loc);
            if(loc == -1){
                return -1;
            }
            int suffixLoc = pContext.indexOf(pSuffix,loc);
            if(suffixLoc == -1){
                continue;
            }
            pResult[0] = pContext.substring(loc,suffixLoc);
            return loc + pPrefix.length();
        }
        return -1;
    }

    private int retrieveNumber(String pString, int pBeg, Number[] pOutNumber){
        StringBuilder sb = new StringBuilder();
        DigitalHandleState digitalHandleState = DigitalHandleState.BEGIN;
        for(int i=pBeg;i<pString.length();i++){
            char c = pString.charAt(i);
            switch (digitalHandleState){
                case BEGIN:
                    if(c == ' '){

                    }else if(c >= '0' && c <= '9'){
                        sb.append(c);
                        digitalHandleState = DigitalHandleState.DIGIT;
                    }else{
                        pOutNumber[0] = null;
                        break;
                    }
                    break;
                case DIGIT:
                    if(c >= '0' && c <= '9'){
                        sb.append(c);
                    }else if(c == '.'){
                        digitalHandleState = DigitalHandleState.FLOAT;
                        sb.append(c);
                    }else{
                        if(sb.length() > 0){
                            pOutNumber[0] = Integer.parseInt(sb.toString());
                        }else{
                            pOutNumber[0] = 0;
                        }
                        return i;
                    }
                    break;
                case FLOAT:
                    if(c >= '0' && c <= '9'){
                        sb.append(c);
                    }else{
                        pOutNumber[0] = Double.parseDouble(sb.toString());
                        return i;
                    }
                    break;
            }
        }
        return 0;
    }


}
